/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.service.dictionary;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.constants.ConstantVars;
import com.je.common.base.constants.dd.DDType;
import com.je.common.base.constants.tree.NodeType;
import com.je.common.base.db.JEDatabase;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.mapper.query.ConditionEnum;
import com.je.common.base.mapper.query.Query;
import com.je.common.base.service.*;
import com.je.common.base.service.rpc.BeanService;
import com.je.common.base.service.rpc.SystemSettingRpcService;
import com.je.common.base.service.rpc.SystemVariableRpcService;
import com.je.common.base.util.StringUtil;
import com.je.common.base.util.TreeUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.cache.dd.DicInfoCache;
import com.je.servicecomb.RpcSchemaFactory;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.sql.Clob;
import java.util.*;

import static com.je.servicecomb.JECloud.*;

/**
 * 抽象字典树服务实现
 */
public abstract class AbstractMetaDictionaryTreeServiceImpl implements MetaDictionaryTreeService {

    private static Logger logger = LoggerFactory.getLogger(AbstractMetaDictionaryTreeServiceImpl.class);

    @Autowired
    protected MetaService metaService;
    @Autowired
    protected MetaRbacService metaRbacService;
    @Autowired
    protected MetaWorkflowService metaWorkflowService;
    @Autowired
    protected BeanService beanService;
    @Autowired
    protected CommonService commonService;
    @Autowired
    protected SystemVariableRpcService systemVariableService;
    @Autowired
    protected SystemSettingRpcService systemSettingRpcService;
    @Autowired
    protected DicInfoCache dicInfoCache;
    @Autowired
    protected QueryBuilderService queryBuilder;
    /**
     * 应用Id
     */
    @Value("${servicecomb.service.application}")
    protected String appId;


    @Override
    public List<JSONTreeNode> findAsyncNodes(DynaBean dictionary, JSONObject obj, String queryType, String value, boolean en, boolean onlyItem) {
        List<JSONTreeNode> array = new ArrayList<>();
        String productCode = dictionary.getStr("SY_PRODUCT_CODE");

        //根节点ID,默认为ROOT
        String rootId = obj.getString("rootId");
        if (StringUtil.isEmpty(rootId)) {
            rootId = ConstantVars.TREE_ROOT;
        }
        //字典编码
        String ddCode = obj.getString("ddCode");
        //字典名称，非必需字段
        String ddName = obj.getString("ddName");
        //字典标识，非必需字段 创建根节点对象ID使用,一次加载多个字典时使用
        String nodeInfo = obj.getString("nodeInfo");
        //默认为1  是否从根节点查找数据
        String isRoot = obj.containsKey("isRoot") ? obj.getString("isRoot") : "1";

        //构建根节点
        JSONTreeNode emptyRoot = new JSONTreeNode();
        emptyRoot.setText(ddName);
        emptyRoot.setParent("ROOT");
        emptyRoot.setId("ROOT_" + nodeInfo);
        emptyRoot.setNodeInfo(nodeInfo);

        //查找字典主表记录
        if (dictionary == null) {
            array.add(emptyRoot);
            throw new PlatformException("未找到数据字典：" + ddCode + "!", PlatformExceptionEnum.JE_CORE_DIC_UNKOWN_ERROR, new Object[]{ddCode});
        }

        //字典类型，本方法支持[外部树形字典，列表字典，树形字典]
        String ddType = dictionary.getStr("DICTIONARY_DDTYPE");
        //字典对应表名，普通列表与普通树形字典此值为空
        String tableName = dictionary.getStr("DICTIONARY_CLASSNAME");
        if (StringUtil.isEmpty(tableName)) {
            tableName = "JE_CORE_DICTIONARYITEM";
        }

        if (!(DDType.TREE.equalsIgnoreCase(ddType) || DDType.LIST.equalsIgnoreCase(ddType))) {
            array.add(emptyRoot);
            logger.error("传入的字典类型出错，字典编码:【" + ddCode + "】!");
            return array;
        }

        //前端sql条件转换
        Query query;
        if (StringUtils.isNotBlank(obj.getString("j_query"))) {
            query = Query.build(obj.getString("j_query"));
        } else {
            query = new Query();
        }

        //获取树形信息
        DynaBean table = beanService.getResourceTable(tableName);
        if (table == null) {
            array.add(emptyRoot);
            return array;
        }

        //构建dyanBean的树形模版
        JSONTreeNode template = beanService.buildJSONTreeNodeTemplate((List<DynaBean>) table.get(BeanService.KEY_TABLE_COLUMNS));
        //普通字典国际化处理
        if ("JE_CORE_DICTIONARYITEM".equals(tableName) && en) {
            template.setText("DICTIONARYITEM_ITEMNAME_EN");
        }

        if ("id".equals(queryType)) {
            query.addCustom(template.getId(), ConditionEnum.IN, value.split(","));
        } else if ("code".equals(queryType)) {
            query.addCustom(template.getCode(), ConditionEnum.IN, value.split(","));
        } else if ("text".equals(queryType)) {
            query.addCustom(template.getText(), ConditionEnum.IN, value.split(","));
        } else if ("liketext".equals(queryType)) {
            query.addCustom(template.getText(), ConditionEnum.LIKE, value);
        } else if ("rootId".equals(queryType)) {
            // 查询指定节点下所有的叶子节点
            rootId = value;
            query.addCustom(template.getNodeType(), ConditionEnum.EQ, "LEAF");
            query.addCustom(template.getNodePath(), ConditionEnum.LIKE, value);
        }

        String adminPermSql = "";
        //条件构建器
        ConditionsWrapper wrapper = query.buildWrapper();
        //获取Admin权限sql
        if (StringUtils.isNotBlank(adminPermSql)) {
            final String sql = adminPermSql;
            wrapper.and(i -> i.apply(queryBuilder.trimSql(sql)));
        }

        if ("JE_CORE_DICTIONARYITEM".equals(tableName)) {
            // 普通字典
            wrapper.eq("DICTIONARYITEM_DICTIONARY_ID", dictionary.getStr("JE_CORE_DICTIONARY_ID"));
            //查找根节点
            if ("1".equals(isRoot)) {
                if (ConstantVars.TREE_ROOT.equals(rootId)) {
                    DynaBean dynaBeanItem = metaService.selectOne("JE_CORE_DICTIONARYITEM",
                            ConditionsWrapper.builder().eq("DICTIONARYITEM_DICTIONARY_ID", dictionary.getStr("JE_CORE_DICTIONARY_ID"))
                                    .eq("SY_NODETYPE", "ROOT"));
                    rootId = dynaBeanItem.getStr("JE_CORE_DICTIONARYITEM_ID");
                }
            }
            wrapper.eq("SY_FLAG", "1");
        }

        //字典配置sql条件
        String ddWhereSql = dictionary.getStr("DICTIONARY_WHERESQL", "");
        String ddOrderSql = dictionary.getStr("DICTIONARY_ORDERSQL", "");

        // 添加字典配置sql
        if (StringUtil.isNotEmpty(ddWhereSql)) {
            //formatSqlParameter 替换Sql中的系统变量 非预处理赋值
            wrapper.apply(queryBuilder.formatSqlParameter(ddWhereSql));
        }

        //排序条件
        String orderSql = query.buildOrder();
        if (StringUtils.isNotBlank(orderSql)) {
            orderSql = " ORDER BY " + orderSql;
        } else if (StringUtils.isNotBlank(ddOrderSql)) {
            orderSql = ddOrderSql;
        }
        wrapper.getParameter().put("orderSql", orderSql);

        //查询数据
        List<JSONTreeNode> jsonTreeNodeList = loadTreeNodeList(ddType, productCode, rootId, tableName, template, wrapper, null, null);
        for (JSONTreeNode eachNode : jsonTreeNodeList) {
            eachNode.setAsync(true);
            if (!Strings.isNullOrEmpty(nodeInfo)) {
                eachNode.setNodeInfo(nodeInfo);
                eachNode.setId(eachNode.getId() + "_" + nodeInfo);
            }
        }
        return jsonTreeNodeList;
    }

    /**
     * 构建一个新树
     * <p>如果集合中存在根节点，则移除<p/>
     *
     * @param lists  树形节点列表，此列表还不存在树形结构
     * @param rootId 根节点ID
     * @return 根节点
     */
    public JSONTreeNode buildJSONNewTree(List<JSONTreeNode> lists, String rootId) {
        JSONTreeNode root = new JSONTreeNode();
        for (JSONTreeNode node : lists) {
            if (node.getParent() == null || "".equals(node.getParent()) || rootId.equals(node.getId())) {
                root = node;
                lists.remove(node);
                break;
            }
        }
        createTreeChildren(lists, root);
        return root;
    }

    /**
     * 递归构建整棵树的结构
     *
     * @param childrens 子节点列表
     * @param root      根节点
     */
    public void createTreeChildren(List<JSONTreeNode> childrens, JSONTreeNode root) {
        String parentId = root.getId();

        //如果子节点为Null或大小为空，则直接返回
        if (childrens == null || childrens.size() == 0) {
            return;
        }

        for (int i = 0; i < childrens.size(); i++) {
            JSONTreeNode node = childrens.get(i);
            if (parentId.equals(node.getParent())) {
                root.getChildren().add(node);
                //当前不能删除节点，因为孩子引用与它， 递归回来，坐标失效
                createTreeChildren(childrens, node);
            }
            if (root.getChildren().size() > 0) {
                root.setLeaf(false);
            } else {
                root.setLeaf(true);
            }
        }

    }

    /**
     * 异步加载树列表集合数据
     *
     * @param rootId       根节点ID
     * @param tableName    资源表名称，如果是列表或树形字典tableName=JE_CORE_DICTIONARYITEM，如果是SQL字典或外部树形字典，则为对应表名
     * @param template
     * @param where
     * @param isRoot
     * @param onlyWhereSql
     * @return
     */
    @Override
    public List<JSONTreeNode> loadAsyncTreeNodeList(String ddType, String product, String rootId, String tableName, JSONTreeNode template, ConditionsWrapper where, Boolean isRoot, Boolean onlyWhereSql) {
        //where 条件
        if (!onlyWhereSql) {
            if ("1".equals(isRoot)) {
                where.and(i -> {
                    i.eq(template.getParent(), rootId).or().eq(template.getId(), rootId);
                });
            } else {
                where.eq(template.getParent(), rootId);
            }
        }
        List<JSONTreeNode> jsonTreeNodes = loadTreeNodeList(ddType, product, rootId, tableName, template, where, null, null);
        for (JSONTreeNode node : jsonTreeNodes) {
            node.setAsync(true);
        }
        return jsonTreeNodes;
    }

    /**
     * 加载
     *
     * @param rootId    根节点ID
     * @param tableName 资源表名称，如果是列表或树形字典tableName=JE_CORE_DICTIONARYITEM，如果是SQL字典或外部树形字典，则为对应表名
     * @param template
     * @param where
     * @return
     */
    public List<JSONTreeNode> loadTreeNodeList(String ddType, String product, String rootId, String tableName, JSONTreeNode template, ConditionsWrapper where) {
        ConditionsWrapper builder = ConditionsWrapper.builder();
        //复制参数
        builder.putAll(where.getParameter());
        //and (nodePath like '%rootId%' and (whereSql)) or id = rootId
        String sql = queryBuilder.trimSql(where.getSql());
        builder.and(i -> {
            i.like(template.getNodePath(), rootId)
                    //语句不为空时拼接
                    .and(j -> j.apply(StringUtils.isNotBlank(sql), sql));
        }).or().eq(template.getId(), rootId);
        return loadTreeNodeList(ddType, product, rootId, tableName, template, builder, null, null);
    }

    /**
     * 加载整棵树的数据，并构建出JsonTreeNode集合，不存在树形结构
     *
     * @param rootId     根节点ID
     * @param tableName  资源表名称，如果是列表或树形字典tableName=JE_CORE_DICTIONARYITEM，如果是SQL字典或外部树形字典，则为对应表名
     * @param template   树形模板
     * @param where      where条件
     * @param includeIds 包含的节点ID
     * @param beanFields 包含的字段，不在此字段范围内的会移除
     * @return 构造的树形数据集合
     */
    @Override
    public List<JSONTreeNode> loadTreeNodeList(String ddType, String product, String rootId, String tableName, JSONTreeNode template, ConditionsWrapper where, List<String> includeIds, String[] beanFields) {
        List<JSONTreeNode> list = new ArrayList<>();
        if (TreeUtil.verify(template)) {
            //拼接sql
            StringBuilder filedSql = new StringBuilder();
            filedSql.append(" select ").append(template.getId()).append(",").append(template.getCode()).append(",").append(template.getText()).append(",").append(template.getParent());
            // 节点类型
            if (StringUtil.isNotEmpty(template.getNodeType())) {
                filedSql.append(",").append(template.getNodeType());
            }
            // 节点信息
            if (StringUtil.isNotEmpty(template.getNodeInfo())) {
                filedSql.append(",").append(template.getNodeInfo());
            }
            // 节点信息类型
            if (StringUtil.isNotEmpty(template.getNodeInfoType())) {
                filedSql.append(",").append(template.getNodeInfoType());
            }
            if (StringUtil.isNotEmpty(template.getLayer())) {
                filedSql.append(",").append(template.getLayer());
            }
            // 图标图片地址
            if (StringUtil.isNotEmpty(template.getIcon())) {
                filedSql.append(",").append(template.getIcon());
            }
            // 图标样式
            if (StringUtil.isNotEmpty(template.getIconColor())) {
                filedSql.append(",").append(template.getIconColor());
            }
            //是否禁用
            if (StringUtil.isNotEmpty(template.getDisabled())) {
                filedSql.append(",").append(template.getDisabled());
            }
            //树形路径
            if (StringUtil.isNotEmpty(template.getNodePath())) {
                filedSql.append(",").append(template.getNodePath());
            }
            //描述
            if (StringUtil.isNotEmpty(template.getDescription())) {
                filedSql.append(",").append(template.getDescription());
            }
            if (StringUtil.isNotEmpty(template.getOrderIndex())) {
                filedSql.append(",").append(template.getOrderIndex());
            }
            if (StringUtil.isNotEmpty(template.getTreeOrderIndex())) {
                filedSql.append(",").append(template.getTreeOrderIndex());
            }

            if (StringUtil.isNotEmpty(template.getOtherBeanFiled().size() > 0)) {
                for (String code : template.getOtherBeanFiled()) {
                    filedSql.append(",").append(code);
                }
            }

            filedSql.append(" FROM ").append(tableName).append(" where ");

            //创建查询
            ConditionsWrapper select = ConditionsWrapper.builder().apply(filedSql.toString());
            //加入传过来的where条件和预处理参数
            select.apply(queryBuilder.trimSql(where.getSql())).putAll(where.getParameter());
            //orderSql
            String orderSql = (String) where.getParameter().getOrDefault("orderSql", "");
            if (StringUtils.isBlank(orderSql)) {
                orderSql = " ORDER BY " + template.getParent() + " asc";
                if (StringUtil.isNotEmpty(template.getOrderIndex())) {
                    orderSql += ", " + template.getOrderIndex() + " asc";
                }
            }
            //添加order
            select.apply(orderSql);

            //执行查询
            List<Map<String, Object>> treeItems = new ArrayList<>();

            if (DDType.SQL.equals(ddType) || DDType.DYNA_TREE.equals(ddType) || DDType.SQL_TREE.equals(ddType)) {
                treeItems = executeRemoteQuery(product, select.getParameterSql());
            } else {
                treeItems = metaService.selectSql(select.getParameterSql());
            }
            //遍历结果构建树形节点对象
            treeItems.forEach(record -> {
                //主键
                String nodeId = (String) record.get(template.getId());
                //排除不在指定节点内的数据
                if (includeIds != null && includeIds.size() > 0 && !includeIds.contains(nodeId)) {
                    return;
                }
                JSONTreeNode node = new JSONTreeNode();
                node.setId(nodeId);
                //名称
                node.setText((String) record.get(template.getText()));
                //编码
                node.setCode((String) record.get(template.getCode()));
                //父节点
                node.setParent((String) record.get(template.getParent()));
                //节点信息
                if (StringUtil.isNotEmpty(template.getNodeInfo())) {
                    node.setNodeInfo(StringUtil.getClobValue(record.get(template.getNodeInfo())));
                }
                //节点信息类型
                if (StringUtil.isNotEmpty(template.getNodeInfoType())) {
                    node.setNodeInfoType(record.get(template.getNodeInfoType()) + "");
                }
                //是否叶子
                if (StringUtil.isNotEmpty(template.getNodeType())) {
                    node.setLeaf(NodeType.LEAF.equalsIgnoreCase(record.get(template.getNodeType()) + ""));
                    node.setNodeType(record.get(template.getNodeType()) + "");
                }
                if (StringUtil.isNotEmpty(template.getLayer())) {
                    node.setLayer(record.get(template.getLayer()) + "");
                }
                //图标图片地址
                if (StringUtil.isNotEmpty(template.getIcon())) {
                    node.setIcon(record.get(template.getIcon()) + "");
                }
                //图标样式
                if (StringUtil.isNotEmpty(template.getIconColor())) {
                    node.setIconColor(record.get(template.getIconColor()) + "");
                }
                //是否禁用
                if (StringUtil.isNotEmpty(template.getDisabled())) {
                    node.setDisabled(record.get(template.getDisabled()) + "");
                } else {
                    node.setDisabled("0");
                }
                //树形路径
                if (StringUtil.isNotEmpty(template.getNodePath())) {
                    node.setNodePath(record.get(template.getNodePath()) + "");
                }
                //描述
                if (StringUtil.isNotEmpty(template.getDescription())) {
                    node.setDescription(StringUtil.getClobValue(record.get(template.getDescription())));
                }
                //排序
                if (StringUtil.isNotEmpty(template.getOrderIndex())) {
                    node.setOrderIndex(record.get(template.getOrderIndex()) + "");
                }
                if (StringUtil.isNotEmpty(template.getTreeOrderIndex())) {
                    node.setTreeOrderIndex(record.get(template.getTreeOrderIndex()) + "");
                }

                //保留指定字段
                if (beanFields != null && beanFields.length > 0) {
                    List<String> fieldList = Arrays.asList(beanFields);
                    Set<String> keySet = record.keySet();
                    for (String key : keySet) {
                        if (!fieldList.contains(key)) {
                            record.remove(key);
                        }
                        ;
                    }

                }

                //如果是oracle则单独处理
                if (JEDatabase.getCurrentDatabase().equals(ConstantVars.STR_ORACLE)) {
                    record.forEach((key, val) -> {
                        if (val == null) {
                            record.put(key, "");
                        } else if (val instanceof Clob) {
                            record.put(key, StringUtil.getClobValue(record.get(key)));
                        }
                    });
                }
                node.setBean(record);
                list.add(node);
            });
        }
        return list;
    }

    protected List<Map<String, Object>> executeRemoteQuery(String product, String sql, Object... params) {
        List<Map<String, Object>> result;
        if (PRODUCT_CORE_META.equals(product)) {
            result = metaService.selectSql(sql, params);
        } else if (PRODUCT_CORE_RBAC.equals(product)) {
            result = metaRbacService.selectMap(sql, params);
        } else if (PRODUCT_CORE_WORKFLOW.equals(product)) {
            result = metaWorkflowService.selectMap(sql, params);
        } else {
            MetaBusService metaBusService = RpcSchemaFactory.getRemoteProvierClazz(product, "metaBusService", MetaBusService.class);
            result = metaBusService.selectMap(sql, params);
        }
        return result;
    }

    public String getQuerySql(String tableCode) {
        String whereSql = "";
        return whereSql;
    }

    protected Map<String, Object> getCustomerVariables(JSONObject obj) {
        Map<String, Object> map = new HashMap<>();
        JSONObject customVariables = null;
        if (obj.containsKey("customVariables")) {
            customVariables = obj.getJSONObject("customVariables");
        }
        if (customVariables != null) {
            for (Map.Entry<String, Object> entry : customVariables.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().toString();
                map.put(key.trim(), value);
            }
        }
        return map;
    }

    protected String buildSqlByCustomVariables(String sql, Map<String, Object> customerVariables) {
        for (String key : customerVariables.keySet()) {
            sql = sql.replace(String.format("{%s}", key), String.valueOf(customerVariables.get(key)));
        }
        return sql;
    }

}
